package fr.neyb.bernouilli.problem011;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class Grid {
	public static Grid parse(Reader r, int suiteLength) throws IOException {
		BufferedReader br = new BufferedReader(r);

		String s;
		List<String> ss = new ArrayList<>();
		while ((s = br.readLine()) != null)
			ss.add(s);

		int[][] content = new int[ss.size()][];

		Pattern splitter = Pattern.compile(" ", Pattern.LITERAL);

		for (int i = 0; i < content.length; i++) {
			String[] linesStringMembers = splitter.split(ss.get(i));
			int[] linesMembers = new int[linesStringMembers.length];

			for (int j = 0; j < linesMembers.length; ++j) {
				linesMembers[j] = Integer.parseInt(linesStringMembers[j]);
			}
			content[i] = linesMembers;
		}

		return new Grid(content, suiteLength);
	}

	private final int[][] content;
	private final int suiteLength;

	private Grid(int[][] content, int suiteLength) {
		this.content = content;
		this.suiteLength = suiteLength;
	}

	public static enum Direction {
		Horizontal, Vertical, RDiagonal, LDiagonal;
	}

	public IntReader getIntReader(Direction direction) {
		switch (direction) {
		case Horizontal:
			return new IntReader(content, suiteLength) {
				@Override
				protected boolean incrCursor() {
					if (cursorPos < content[cursorLine].length - 1) {
						++cursorPos;
						return false;
					} else {
						if (cursorLine < content.length - 1) {
							++cursorLine;
							cursorPos = 0;
						} else {
							cursorLine = -1;
							cursorPos = -1;
						}
						return true;
					}
				}
			};

		case Vertical:
			return new IntReader(content, suiteLength) {
				@Override
				protected boolean incrCursor() {
					if (cursorLine < content.length - 1) {
						++cursorLine;
						return false;
					} else {
						if (cursorPos < content[cursorLine].length - 1) {
							++cursorPos;
							cursorLine = 0;
						} else {
							cursorPos = -1;
							cursorLine = -1;
						}
						return true;
					}
				}
			};

		case RDiagonal:
			return new IntReader(content, suiteLength) {
				@Override
				protected boolean incrCursor() {
					if (cursorLine < content.length - 1
							&& cursorPos < content[cursorLine].length - 1) {
						++cursorLine;
						++cursorPos;
						return false;
					} else {
						if (cursorPos == 0) {// on est dans un angle de fin
							cursorLine = -1;
							cursorPos = -1;
						} else {
							if (cursorLine >= cursorPos) {
								cursorPos = cursorLine - cursorPos + 1;
								cursorLine = 0;
							} else {
								cursorLine = cursorPos - cursorLine;
								cursorPos = 0;
							}
						}
						return true;
					}
				}
			};

		case LDiagonal:
			return new IntReader(content, suiteLength) {
				@Override
				protected boolean incrCursor() {
					if (cursorLine < content.length - 1 && cursorPos > 0) {
						++cursorLine;
						--cursorPos;
						return false;
					} else {
						if (cursorPos == 0 && cursorLine == content.length - 1) {
							// on est dans un angle de fin
							cursorLine = -1;
							cursorPos = -1;
						} else {
							if (cursorPos <= 0) {
								cursorLine = content.length - 1 - cursorLine;
								cursorPos = content[cursorLine].length - 1;
							} else {
								cursorPos = content[0].length - cursorPos;
								cursorLine = 0;
							}
						}
						return true;
					}
				}
			};
		default:
			return null;
		}
	}
}
